//
//  Main.cpp
//  BaseDemo
//
//  Created by jiuyv on 2019/5/8.
//  Copyright © 2019 Julija. All rights reserved.
//正背面剔除,深度测试,多边形模式

#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLGeometryTransform.h"

#include <glut/glut.h>
#include <stdio.h>


//设置角色帧,作为相机
GLFrame     viewFrame;
//使用GLFrustum类来设置透视视图
GLFrustum   viewFrustum;
GLTriangleBatch     torusBatch;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transforPipeline;
GLShaderManager shaderManager;


//标记:背面剔除,深度测试
int iCull = 0;
int iDepth = 0;

void ChangeSize(int w, int h){
    //设置窗口尺寸
    glViewport(0, 0, w, h);
    
    //设置透视模式,初始化其透视矩阵
    viewFrustum.SetPerspective(35, float(w)/float(h), 1, 100);
    
    //把透视矩阵加载到 透视矩阵堆栈中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //初始化渲染管线
    transforPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

void SetupRC(){
    //设置背景颜色 蓝色
    glClearColor(0.04, 0.42, 1.00, 1.00);
    
    //初始化着色器管理器
    shaderManager.InitializeStockShaders();
    
    //将相机向后移动7个单元:肉眼和物体之间的距离
    viewFrame.MoveForward(7.0);
    
    //创建一个甜甜圈
//    gltMakeTorus(torusBatch, 1.0, 0.3, 40, 20);
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    
    //设置点大小
    glPointSize(4.0f);
}

void RenderScene(void){
    //清除一个或一组特定缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //开启/关闭正背面剔除
    if (iCull) {
        glEnable(GL_CULL_FACE);
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
    }
    else{
        glDisable(GL_CULL_FACE);
    }
    //开启/关闭深度测试
    if (iDepth) {
        glEnable(GL_DEPTH_TEST);
    }
    else{
        glDisable(GL_DEPTH_TEST);
    }
    
    //把摄像机矩阵压入模型矩阵中
    modelViewMatrix.PushMatrix(viewFrame);
    
    //这是绘图颜色
    GLfloat vRed[] = {1.0f,0.0f,0.0f,1.0f};
    /*
     使用平面着色器
     参数1:平面着色器
     参数2:模型试图矩阵
     参数3:颜色
     */
//    shaderManager.UseStockShader(GLT_SHADER_FLAT,transforPipeline.GetModelViewProjectionMatrix(),vRed);
    
   /*使用默认投影矩阵
    参数1:
    */
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT,transforPipeline.GetModelViewMatrix(),transforPipeline.GetProjectionMatrix(),vRed);
    
    //绘制
    torusBatch.Draw();
    
    //出栈 绘制完成恢复
    modelViewMatrix.PopMatrix();
    
    //交换缓冲区
    glutSwapBuffers();
    
}

void SpecialKeys(int key, int x, int y){
    if (key == GLUT_KEY_UP) {
        viewFrame.RotateWorld(m3dDegToRad(5), 1, 0, 0);
    }
    if (key == GLUT_KEY_DOWN) {
        viewFrame.RotateWorld(m3dDegToRad(-5), 1, 0, 0);
    }
    if (key == GLUT_KEY_LEFT) {
        viewFrame.RotateWorld(m3dDegToRad(-5), 0, 1, 0);
    }
    if (key == GLUT_KEY_RIGHT) {
        viewFrame.RotateWorld(m3dDegToRad(5), 0, 1, 0);
    }
    glutPostRedisplay();
}

void PressMenu(int value){
    switch (value) {
        case 1:
            iCull = !iCull;
            break;
        case 2:
            iDepth = !iDepth;
            break;
        case 3:
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            break;
        case 4:
            glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
            break;
        case 5:
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            break;
    }
    glutPostRedisplay();
}

int main(int argc, char* argv[]){
    
    //设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    
    //初始化GLUT库
    glutInit(&argc, argv);
    
    //初始化缓冲区窗口,其中标志GLUT_DOUBLE GLUT_RGBA GLUT_DEPTH GLUT_STENCIL 分别指 双缓冲区 颜色缓冲区 深度缓冲区 模板缓冲区
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    
    glutInitWindowSize(600, 600);
    
    glutCreateWindow("BaseDemo");
    
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    
    glutDisplayFunc(RenderScene);
    
    glutSpecialFunc(SpecialKeys);
    
    //添加右击菜单
    glutCreateMenu(PressMenu);
    glutAddMenuEntry("Cull BackFace", 1);
    glutAddMenuEntry("Depth Test", 2);
    glutAddMenuEntry("Fill Model", 3);
    glutAddMenuEntry("Point Model", 4);
    glutAddMenuEntry("Line Model", 5);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    //驱动程序初始化过程中是否出现问题
    GLenum error = glewInit();
    if (GLEW_OK != error) {
        fprintf(stderr, "glew error:%s\n",glewGetErrorString(error));
        return 1;
    }
    
    SetupRC();
    
    glutMainLoop();
    
    return 0;
}

